function main()
%main(stream_file, me0_param_file, me1_param_file, me_hier_param_file,
%vp_param_file, mc_param_file)
[filename, pathname, filterindex] = uigetfile( ...
       {'*.avi;*.mp4;*.mpg;*.div; *.divx', 'all video stream files(*.avi, *.mp4, *.mpg, *.div, *.divx)';...
        '*.*',  'All Files (*.*)'}, ...
        'Pick a file');
stream_file = [pathname, filename];%'SlippingGirl_24P.mpg'; %'./Valley of fire.mpg'; %'./Fast.Furious.1080P.wmv';
stream_start  = 5;
output_frames = 10; %250;
output_rate   = 60;

lr_ratio = 4;

result_dir = './result/';

pattern = [1 1];%[1 0 0 1 0];
ptn_num = length(pattern);
ptn_idx = 1;

h_wb = waitbar(0,'in processing, 0% done, please wait...'); %create wait bar
vo_obj_ph0 = gen_output_vobj([result_dir,'out_ph0.avi'],output_rate); %generate output object
vo_obj_ph1 = gen_output_vobj([result_dir,'out_ph1.avi'],output_rate); %generate output object
vo_obj_m   = gen_output_vobj([result_dir,'out_mask.avi'],output_rate);

frame = get_frame(stream_file, pattern, stream_start);
frame = get_frame;% should be sizey by sizex by 3 picture
yuv_pre   = permute(rgb2ycbcr(frame.cdata), [2 1 3]); %should be sizex by sizey by 3 
new_flag = 0;
while ~new_flag
    [frame, new_flag] = get_frame;
end
yuv_cur   = permute(rgb2ycbcr(frame.cdata), [2 1 3]); %should be sizex by sizey by 3
ptn_idx = 4;
[pic_size(1), pic_size(2), nouse] = size(yuv_cur);
block_size = [8,8];
block_number = ceil(pic_size ./ block_size);

me_param = init_me_param (block_size, block_number, [lr_ratio lr_ratio]);
lr_me_param = init_me_param(block_size, ceil(block_number/lr_ratio), [1 1]);
lr_pic_size = block_size .* ceil(block_number/lr_ratio);
me_param_ph0 = me_param; me_param_ph0.temp_phase = uint8(0);  me_param_ph0.meander_en = uint8(1);me_param_ph0.pred_mode = uint8(0);me_param_ph0.fs_en = uint8(0);me_param_ph0.aplap_en = uint8(1);
me_param_ph1 = me_param; me_param_ph1.temp_phase = uint8(128);me_param_ph1.meander_en = uint8(1);me_param_ph1.pred_mode = uint8(0);me_param_ph1.fs_en = uint8(0);me_param_ph1.aplap_en = uint8(1);
me_param_lr  = lr_me_param; me_param_lr.temp_phase = uint8(0);me_param_lr.meander_en = uint8(1); me_param_lr.pred_mode  = uint8(0); me_param_lr.fs_en = uint8(0) ;me_param_lr.aplap_en = uint8(0);

mc_param = init_mc_param (block_size, block_number);

vp_param    = init_vp_param (block_size, block_number);
logo_param  = init_logo_param(block_number);
lr_vp_param = init_vp_param (block_size*4, ceil(block_number/4));lr_vp_param.temp_phase = uint8(64);
vp_param_ph0 = vp_param;
vp_param_ph1 = vp_param;
vp_param_lr  = lr_vp_param;


polarity_pre = uint8(0); polarity_cur = uint8(0);
frame_format = uint8(0);


tsum = 0;
tic;
for (idx = 1 : output_frames)
    [frame, new_flag] = get_frame;

    if(new_flag)
        yuv_pre = yuv_cur;
        yuv_cur = permute(rgb2ycbcr(frame.cdata), [2 1 3]);
    end
    %do me
    tstart = tic;
    lr_yuv_pre = imresize(yuv_pre,0.25, 'triangle');
    lr_yuv_cur = imresize(yuv_cur,0.25, 'triangle');
    me_result_ph0 = me(yuv_pre, polarity_pre, yuv_cur, polarity_cur, frame_format, me_param_ph0);
    me_result_ph1 = me(yuv_pre, polarity_pre, yuv_cur, polarity_cur, frame_format, me_param_ph1);
    me_result_lr  = me(lr_yuv_pre, polarity_pre, lr_yuv_cur, polarity_cur, frame_format, me_param_lr);

    
    vp_param_ph0.pre_vector = vp_param_ph0.cur_vector;
    vp_param_ph0.cur_vector = me_result_ph0.vector;
    if(new_flag)
    vp_param_ph0.pre_sad    = vp_param_ph0.cur_sad;
    vp_param_ph0.cur_sad    = me_result_ph0.SAD;
    vp_param_ph0.pre_apl    = vp_param_ph0.cur_apl;
    vp_param_ph0.cur_apl    = me_result_ph0.APL;
    vp_param_ph0.pre_dtl    = vp_param_ph0.cur_dtl;
    vp_param_ph0.cur_dtl    = me_result_ph0.detail;
    vp_param_ph0.cuc_pre_ph1_vec ...
                            = me_result_ph1.vector;
        if(idx ~= 1)
            vp_param_ph0.cuc_pre_uncov_mask ...
                            = vp_result.uncover_mask;
        end
    end

    vp_param_ph1.pre_vector = vp_param_ph1.cur_vector;
    vp_param_ph1.cur_vector = me_result_ph1.vector;
    if(new_flag)
    vp_param_ph1.pre_sad    = vp_param_ph1.cur_sad;
    vp_param_ph1.cur_sad    = me_result_ph1.SAD;
    vp_param_ph1.pre_apl    = vp_param_ph1.cur_apl;
    vp_param_ph1.cur_apl    = me_result_ph1.APL;
    vp_param_ph1.pre_dtl    = vp_param_ph1.cur_dtl;
    vp_param_ph1.cur_dtl    = me_result_ph1.detail;
    vp_param_ph1.cuc_pre_ph1_vec ...
                            = me_result_ph1.vector;
        if(idx ~= 1)
            vp_param_ph1.cuc_pre_uncov_mask ...
                            = vp_result.uncover_mask;
        end
    end
    
    vp_param_lr.pre_vector = vp_param_lr.cur_vector;
    vp_param_lr.cur_vector = me_result_lr.vector;
    if(new_flag)
    vp_param_lr.pre_sad    = vp_param_lr.cur_sad;
    vp_param_lr.cur_sad    = me_result_lr.SAD;
    vp_param_lr.pre_apl    = vp_param_lr.cur_apl;
    vp_param_lr.cur_apl    = me_result_lr.APL;
    vp_param_lr.pre_dtl    = vp_param_lr.cur_dtl;
    vp_param_lr.cur_dtl    = me_result_lr.detail;
    end
    
    vp_result = vp(vp_param_ph0, vp_param_ph1, vp_param_lr, logo_param);
    mc_param.vector = vp_result.mc_vector;
    mc_param.cuc_mask = vp_result.cuc_mask;
    mc_param.logo_mask = vp_result.logo_mask;
    mc_param.temp_phase = uint8(64);
    YUVmc = mc(yuv_pre, polarity_pre, yuv_cur, polarity_cur,mc_param);
    logo_param.static_history    = vp_result.static_history;
    logo_param.cont_motion_count = vp_result.cont_motion_count;
    
    %me_result = me(yuv_cur, polarity_pre, yuv_cur, polarity_cur, frame_format, me_param);
    tsum = toc(tstart)+tsum;
    %yuv_draw = imresize(yuv_cur, 0.5);
    %draw_image(yuv_pre(:,:,1), yuv_pre(:,:,2), yuv_pre(:,:,3), block_size, [128, 0, 128], [], [], 0.5);hold;
    %draw_motion_field(me_result_ph0.vector, block_size);
    %draw_image(yuv_pre(:,:,1), yuv_pre(:,:,2), yuv_pre(:,:,3), block_size, [128, 0, 128], [], [], 0.5);hold;
    %draw_motion_field(vp_result.ph0_vector, block_size);
    yuv_vol_ph0 = vector_overlay(yuv_pre, me_result_ph0.vector, 1, 0.4);
    %draw_image(yuv_cur(:,:,1), yuv_cur(:,:,2), yuv_cur(:,:,3), block_size, [128, 0, 128], [], [], 0.5);hold;
    %draw_motion_field(me_result_ph1.vector, block_size);
    yuv_vol_ph1 = vector_overlay(yuv_cur, me_result_ph1.vector, 1, 0.4);
    %draw_image(lr_yuv_cur(:,:,1), lr_yuv_cur(:,:,2), lr_yuv_cur(:,:,3), block_size, [128, 0, 128], [], [], 0.5);hold;
    %draw_motion_field(me_result_lr.vector, block_size);
    %yuv_mol = mask_overlay(yuv_cur, double(me_result.SAD), 0.25, 0.5);
    %yuv_mol = mask_overlay(yuv_cur, vp_result.static_history*4, 0.25, 0.8);
    yuv_mol = mask_overlay(yuv_cur, vp_result.logo_mask*255, 0.25, 0.8);
    rgb_mout = permute(ycbcr2rgb(yuv_mol), [2 1 3]);
    vo_obj_m = addframe(vo_obj_m, rgb_mout);
    %output frame
    rgb_out_ph0 = permute(ycbcr2rgb(yuv_vol_ph0), [2 1 3]);
    vo_obj_ph0 = addframe(vo_obj_ph0, rgb_out_ph0);
    rgb_out_ph1 = permute(ycbcr2rgb(yuv_vol_ph1), [2 1 3]);
    vo_obj_ph1 = addframe(vo_obj_ph1, rgb_out_ph1);    
    %update wait bar
    msg = ['in processing, ', num2str(idx/output_frames*100), '% done, please wait...'];
    me_param_ph0.prev_vec  =  me_result_ph0.vector;
    me_param_ph0.prev_sad  =  me_result_ph0.SAD;
    me_param_ph0.prev_lr_vec  =  me_result_lr.vector;
    me_param_ph0.prev_lr_sad  =  me_result_lr.SAD;
    me_param_ph0.flipud_en = ~me_param_ph0.flipud_en;


    me_param_ph1.prev_vec  =  me_result_ph1.vector;
    me_param_ph1.prev_sad  =  me_result_ph1.SAD;
    me_param_ph1.prev_lr_vec  =  me_result_lr.vector;
    me_param_ph1.prev_lr_sad  =  me_result_lr.SAD;
    me_param_ph1.flipud_en = ~me_param_ph1.flipud_en;

    me_param_lr.prev_vec   =  me_result_lr.vector;
    me_param_lr.prev_sad   =  me_result_lr.SAD;
    me_param_lr.flipud_en  = ~me_param_lr.flipud_en;
    
    if(new_flag)
    me_param_ph0.prev_apl  =  me_result_ph0.APL;
    me_param_ph0.prev_dtl  =  me_result_ph0.detail;
    me_param_ph0.prev_lr_apl  =  me_result_lr.APL;
    me_param_ph0.prev_lr_dtl  =  me_result_lr.detail;
    me_param_ph1.prev_apl  =  me_result_ph1.APL;
    me_param_ph1.prev_dtl  =  me_result_ph1.detail;
    me_param_ph1.prev_lr_apl  =  me_result_lr.APL;
    me_param_ph1.prev_lr_dtl  =  me_result_lr.detail;
    me_param_lr.prev_apl   =  me_result_lr.APL;
    me_param_lr.prev_dtl   =  me_result_lr.detail;
    end
    
    waitbar(idx/output_frames, h_wb, msg);
end
tall = toc;
vo_obj_ph0 = close(vo_obj_ph0);
vo_obj_ph1 = close(vo_obj_ph1);
vo_obj_m   = close(vo_obj_m);
close(h_wb);
uiwait(msgbox(['Process Finished,me cost ', num2str(tsum), ', total cost' num2str(tall)],'MEMC Done','modal'));

function vobj = gen_output_vobj(file_name,rate)
vobj = avifile(file_name);
vobj.fps         = rate;
vobj.compression = 'Indeo5';
vobj.quality     = 100; 

function vp_param = init_vp_param (block_size, block_number)
vp_param = struct('block_size', uint8(block_size),...  % size in original picture
                  'block_number', uint16(block_number),...
                  'temp_phase', uint8(0),...
                  'vec_precision', uint8([2,2]), ... %[2^2, 2^2]
                  'cur_vector', int16(zeros([block_number,2])), ...
                  'cur_sad', uint32(zeros(block_number)), ...
                  'cur_apl', uint8(zeros(block_number)), ...
                  'cur_dtl', uint16(zeros(block_number)), ...
                  'pre_vector', int16(zeros([block_number,2])), ...
                  'pre_sad', uint32(zeros(block_number)), ...
                  'pre_apl', uint8(zeros(block_number)), ...
                  'pre_dtl', uint16(zeros(block_number)), ...
                  'vp_order', uint8(0), ...
                  'ss_en', uint8(0), ...
                  'ss_thr', uint16(12), ...
                  'ts_en', uint8(0), ...
                  'ts_thr', uint16(12), ...
                  'med_en', uint8(1), ...
                  'med_mode', uint8(1), ...
                  'med_aam_apl_diff', uint8(32), ...
                  'aav_en', uint8(1), ...        %in avv_range, if apl_diff > avv_apl_diff_thr and vec_diff > vec_diff_thr, adjust vector
                  'aav_range', uint8(4), ...
                  'aav_apl_consist_thr', uint8(32), ...
                  'aav_apl_diff_thr', uint8(48), ...  
                  'aav_vec_diff_thr', uint16(32),...
                  'cuc_delta_thr', uint8(96), ...
                  'cuc_dlt_diff_thr',uint8(48), ...
                  'cuc_fill_en', uint8(1), ...
                  'cuc_fill_lr_thr', uint8(3), ...
                  'cuc_fill_thr', uint8(9), ...
                  'cuc_ext_en', uint8(1), ...
                  'cuc_rm_thr', uint8(4), ...
                  'cuc_vec_rep_en', uint8(1), ...
                  'cuc_pre_ph1_vec', int16(zeros([block_number,2])), ...
                  'cuc_no_uc_overrep_en', uint8(0), ...
                  'cuc_no_uc_overrep_thr', uint16(96), ...
	              'cuc_pre_uncov_mask', uint8(zeros(block_number)) ...
                  );
              
function logo_param = init_logo_param(block_number)
logo_param = struct('static_history', uint8(zeros(block_number)), ...
	               'cont_motion_count', uint8(zeros(block_number)), ...
	               'vec_static_thr', uint16(8), ...
	               'vec_motion_thr', uint16(8), ...
                   'static_inc_step', uint8(5), ...
                   'motion_dec_step', uint8([1, 2, 3, 4]),...
                   'logo_history_thr', uint8(8), ...
	               'lr_nb55_noflat_thr', uint16(10), ...
	               'lr_nb55_motion_thr', uint16(2), ...
                   'fill_en', uint8(1),...
                   'ext_en', uint8(1),...
                   'logo_ext_thr', uint8(3),...
                   'retimer_phase', uint8(64),...
                   'good_vec_diff_thr', uint16(64),...     
                   'bad_vec_diff_thr', uint64(512)...  
                   );
               
function mc_param = init_mc_param(block_size, block_number)
mc_param = struct('temp_phase', uint8(64),                ...%128 totally, 0 @previous, 128 @ current
	'block_size', uint8(block_size),        ...%
	'block_number', uint16(block_number),    ...%
	'vector', int16(zeros([block_number, 2])),...   %
	'vec_precision', uint8([2,2]),          ...% 1<<vec_precision[0], 1<<vec_precision[1]
	'obmc_en', uint8(1),                    ...%
	'obmc_vardiff_thr', uint16(8),          ...%var_diff > obmc_vardiff_thr, do obmc
	'obmc_vardiff_trans', uint8(32),         ...%obmc tap up/dn, left/right coef = coef * |vdiff| * obmc_vardiff_trans
	'refine_en', uint8(1),                  ...% refine vector from bv + update if vector has good consistency
	'refine_dir_en', uint8(1),              ...% refine vector, update vector in vector major direction
	'refine_cent_only', uint8(0),           ...% 1: use cent vector as refine base; 0: use mean of neighbor vector as refine base
	'refine_vardiff_thr', uint8(16),        ...% var_diff < refine_vardiff_thr, do refine
	'refine_length', uint8([2,2]),          ...% 2
	'refine_dir_minvec_th', uint8(32),      ...% vx+vy > refine_dir_minvec_th enable directional refine
	'refine_dir_mindiff_th', uint8(12),     ...% diff_of_vx_vy min/max threshold is used to decide 
	'refine_dir_maxdiff_th', uint8(16),     ...
	'cuc_en', uint8(1),                     ...%cover/uncover protect enable
	'cuc_low_cnt_thr',uint8(2),             ...% in 3x3 neighbor, cover > hi_thr and uncover < lo_thr, center block is cover; uncover > hi_th and cover < lo_th, cent block is uncover.
	'cuc_hi_cnt_thr', uint8(3),             ...%
	'cuc_alpha_en', uint8(0),               ...% not use now
	'logo_en', uint8(0),                    ...% protect logo
    'logo_ext_range', uint8([2 1]),         ...% logo extension range
    'logo_hit_range', uint8([2 1]),         ...% if in +-logo_hit_range there is a block, logo is hitted
    'logo_tuning_vec_en', uint8(0),         ...% if enable, in logo area, vector should be reduced.
	'oob_en', uint8(1),                     ...% out of boundary protect enable, the boundary should be picture and window
	'oob_vec_range', uint8([256, 128]),     ...% vector range, not used so far.
    'cuc_mask', int8(zeros(block_number)),  ...% cuc mask, -1: cover; 1 uncover; 7 CUC conflict; 5: bad vector; 3:good vector
	'logo_mask', uint8(zeros(block_number)),...%
    'out_sel', uint8(0),                    ...%0: (p+c)/2;  1: P; 2:C; 3:PC0; 4:P0; 5:C0;
	'window',    uint16([2, 1917, 2, 1077]),... %0:3  l_x, r_x, t_y, b_y, counter from 0
    'good_prot_en', uint8(1),               ...%enable good area blend
    'bad_prot_en', uint8(1),                ...%enable bad area blend
    'y_overlay_mode', uint8(0),             ...%y overlay mode
    'uv_overlay_mode', uint8(0),            ...%uv overlay mode
    'ol_ku',           uint8(1),            ...%u factor
	'ol_kv',uint8(1),                       ...%v factor
	'grid_en', uint8(0)                     ...%enable show grid
    ); 
  
        
function me_param = init_me_param (block_size, block_number, block_ratio)
lr_block_number = ceil(block_number./block_ratio);
me_param = struct(     'block_size', uint8(block_size),...
                       'block_number', uint16(block_number),...
                       'overlap', uint8([4,4]), ...
                       'flipud_en', uint8(0), ...
                       'meander_en', uint8(0), ...
                       'pred_mode', uint8(0), ...
                       'pred_sad_factor', uint8(128),...
                       'pred_en',   uint8([0 1 1 1 1 1 1 1]), ...
                       'update_en', uint8([0 1 1 1 0 0 0 0]), ...
                       'pred_pos', int8([0, 0,   -1, -1,   0,-1,   1,-1,   -1, 0,  1, 0,  -2, 2,  2, 2]), ...
                       'pred_penalty', uint16([0, 0, 0, 0, 0, 32, 32, 32]),...
                       'update_penalty', uint16(64), ...
                       'update_level', uint8([1,1]),...
                       'zero_en', uint8(1), ...
                       'zero_penalty', uint16(512),...
                       'afm_en', uint8(0),...
                       'afm_param', int16([15, -25, 35, -11135, 11125, -11115]),...
                       'afm_penalty', uint16(29),...
                       'prev_vec', int16(zeros([block_number,2])),...
                       'prev_apl', uint8(zeros(block_number)), ...
                       'prev_sad', uint32(zeros(block_number)), ...
                       'prev_dtl', uint16(zeros(block_number)), ...
                       'prev_lr_vec', int16(zeros([lr_block_number,2])),...
                       'prev_lr_apl', uint8(zeros(lr_block_number)), ...
                       'prev_lr_sad', uint32(zeros(lr_block_number)), ...
                       'prev_lr_dtl', uint16(zeros(lr_block_number)), ...
                       'lr_block_ratio', block_ratio, ...
                       'y_only', uint8(1),...
                       'vec_precision', uint8([2,2]), ... %[2^2, 2^2]
                       'temp_phase', uint8(64), ...  %0:pre  128:cur, 
                       'cuc_sad_diff_thr_k', uint8(2), ...
                       'cuc_sad_diff_thr', uint16(64), ...
                       'cuc_sad_thr', uint32(128), ...
                       'same_temp_en', uint8(0), ...
                       'cur_high_priority', uint8(1), ...
                       'same_temp_penalty', uint16(10),...
                       'fs_en', uint8(0), ...
                       'fs_penalty', uint16(2048), ...
                       'fs_step', uint16([32, 128, 64, 96, 48, 16, 80, 112]),...
                       'aplap_en', uint8(0),...    % if in temp 5x5 window, (apl_diff_min_max > thr & v_diff_in_apl_min_max > aplap_mm_vec_diff_thr) penalty += aplap_vdiff_factor * vdiff
                       'aplap_vdiff_factor', uint8(32),...
                       'aplap_mm_apl_diff_thr', uint8(24), ...
                       'aplap_mm_vec_diff_thr', uint16(32),...
                       'lrpred_en', uint8(0),...
                       'lrp_penalty', uint16(64*16), ...
                       'lrp_k_dtl', uint8(0),...
                       'lrp_k_apl', uint8(0) ...
                       );
%me_param.prev_vec        = int16(zeros([block_number,2]));
%me_param.prev_vec(:,:,1) = int16([1:block_number(1)]'*ones(1, block_number(2)));
%me_param.prev_vec(:,:,2) = int16(ones(block_number(1),1)*[1:block_number(2)]);

